package es.deusto.ingenieria.is.search.tsp.main;


import es.deusto.ingenieria.is.search.formulation.Operator;
import es.deusto.ingenieria.is.search.formulation.State;
import es.deusto.ingenieria.is.search.tsp.algorithms.blind.UniformedCostSearch;
import es.deusto.ingenieria.is.search.tsp.formulation.AnadirCiudad;
import es.deusto.ingenieria.is.search.tsp.formulation.Ciudad;
import es.deusto.ingenieria.is.search.tsp.formulation.EnvironmentMap;
import es.deusto.ingenieria.is.search.tsp.formulation.ProblemaTSP;
import es.deusto.ingenieria.is.tsp.formulation.heuristics.DistanciaManhattan;


/**
 * @author Kevin e Inigo
 *
 * Clase main del proyecto, en la cual probamos el correcto funcionamiento de cada m�todo implementado.
 */
public class MainProgram {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		try {

			/**Prueba de gatherInitial. Llamamos al toString del Enviroment para comprobar su funcionamiento correcto.
			 * Inicialmente deben aparecer todas las ciudades como no visitadas exceptuando la inicial y la final.
			 **/
			ProblemaTSP pts= new ProblemaTSP();
			State st=pts.gatherInitialPercepts();
			pts.addInitialState(st);

			EnvironmentMap env=(EnvironmentMap) st;

			/**Prueba effect. Para ello creamos una ciudad auxiliar en la que guardamos la ultima ciudad del array de No Visitadas.
			 * Dicha ciudad seria la siguiente a visitar, mediante la clase anadirCiudad. Finalmenta comprobamos si el metodo effect a 
			 * funcionado comparando la ciudad guardad anteriormente con la ultima posici�n del array de No visitadas.
			 */
			Ciudad aux = env.ciudadesNoVisitadas.get(env.ciudadesNoVisitadas.size()-1);
			AnadirCiudad ac=new AnadirCiudad(aux);
			EnvironmentMap nuevo=ac.prueba(env);
			System.out.println("*Son la misma ciudad tras el effect: " + 
					aux.equals(nuevo.ciudadesNoVisitadas.get(nuevo.ciudadesNoVisitadas.size()-1)));
			System.out.println();

			/**
			 * Pueba isApplicable. Comprobamos si en el enviroment pasado como parametro ya se ha efectuado la accion. En ese caso
			 * sacar por pantalla true. Si no es false y se puede realizar la acci�n. 
			 */
			ac.pruebaAplicable(nuevo);

			/**
			 * Prueba isFinalState. Comprueba si dicho estado es el final, es decir si todas las ciudad han sido visitadas y hemos llegado a
			 * la ciudad final. FinalState comprobacion: falso
			 */
			System.out.println("*Es el �ltimo estado: " + pts.isFinalState(st));
			System.out.println();

			/**
			 * Ahora borramos todas las ciudades del array de No Visitadas para simular que todas ellas han sido visitadas. Y de nuevo
			 * comprobamos si es estado final. FinalState comprobacion: verdadero
			 */
			for(int i = 0 ; i < nuevo.getCiudadesNoVisitadas().size(); i++){

				System.out.println("Borramos " + env.ciudadesNoVisitadas.remove(0));
			}

			System.out.println();
			System.out.println("*Es el �ltimo estado: " + pts.isFinalState(st));

			System.out.println();

			/**
			 * Anadimos todos lo operadores posibles y vamos sacando por pantalla su info.
			 */
			System.out.println("*Operadores a�adidos: ");
			for (Operator o :pts.getOperators())
			{
				System.out.println("\t" + o.getName());
			}
			for (State s: pts.getInitialStates())
			{
				System.out.println(s);
			}


		} catch (Exception ex) {
			System.err.println("% [Main Program] Error: " + ex.getMessage());
			ex.printStackTrace();
		}
		//Probamos el funcionamiento de busqueda
		try {		
			/* COMENTARIO: Realizamos las diferentes búsquedas y comprobamos que la distancia acumulada es
			 * correcta, es por ello que la calculamos de nuevo.
			 */
			ProblemaTSP problem = new ProblemaTSP();
			//BÚSQUEDA EN PROFUNDIDAD
			//problem.solve(DepthFS.getInstance());
			//BÚSQUEDA A LO ANCHO
			//problem.solve(BreadthFS.getInstance());	
			//BÚSQUEDA BEST FIRST
			//problem.solve(new BestFS(new DistanciaEvaluationFunction()));
			//BÚSQUEDA UNIFORME
			//problem.solve(new UniformedCostSearch(new DistanciaLineaRecta()));
			problem.solve(new UniformedCostSearch(new DistanciaManhattan()));


			System.out.println("Coste total: "+problem.getTotalCost() +"="+((EnvironmentMap)problem.getFinalStates().get(0)).costeTotal);
//			System.out.println("La distancia de Manhattan: "+((EnvironmentMap)problem.getFinalStates().get(0)).getDistanciaManhattanTotal());
		} catch (Exception ex) {
			System.err.println("% [MainProgram] Error: " + ex.getMessage());
			ex.printStackTrace();
		}
	}
}
